#pragma once

//#include "NetSession.h"
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>

template <class NET_SESSION>
class NetServer : private boost::noncopyable
{
public:  
    NetServer(const unsigned short port) : port_(port), 
        acceptor_(service_), session_(new NET_SESSION(service_))
    {
    }


    void Open(unsigned short port, bool reuse = true)
    {
        port_ = port;
        boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(), port);
        boost::system::error_code ec;
        acceptor_.open(ep.protocol(), ec);
        boost::asio::detail::throw_error(ec);
        if (reuse) {
            acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec);
            boost::asio::detail::throw_error(ec);
        }
        acceptor_.bind(ep, ec);
        boost::asio::detail::throw_error(ec);
        acceptor_.listen(boost::asio::socket_base::max_connections, ec);
        boost::asio::detail::throw_error(ec);

        acceptor_.async_accept(session_->Socket(),
            boost::bind(&NetServer::handle_accept, this,
            boost::asio::placeholders::error));
    }

    void Run()
    {
        try
        {
            std::cout << "Run Server : port(" << port_ << ")" << "\n";
            service_.run();
        }
        catch (std::exception& e)
        {
            std::cerr << "Exception: " << e.what() << "\n";
        }
    }

    void Stop()
    {
        std::cout << "Stop Server : port(" << port_ << ")" << "\n";
        service_.stop();
    }

protected:
    virtual void handle_accept(const boost::system::error_code& error)
    {
        if (error) {
            std::cerr << error.message() << "\n";
            return;
        }

        session_->Start();
        session_.reset(new NET_SESSION(service_));
        acceptor_.async_accept(session_->Socket(),
            boost::bind(&NetServer::handle_accept, this,
            boost::asio::placeholders::error));
    }

protected:
    typedef boost::shared_ptr<NET_SESSION> NetSessionPtr;

    unsigned short port_;

    boost::asio::io_service service_;
    boost::asio::ip::tcp::acceptor acceptor_;

    NetSessionPtr session_;
};
